﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using System.Xml;
using System.Xml.Schema;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using EFFC.Net.Exceptions;
using System.Runtime.Serialization;
using System.Reflection;


namespace EFFC.Net.Parameters
{
    [Serializable]
    public class PElementXmlSerializtion : IXmlSerializable
    {
        static string ns = "http://www.WITS.com/Frame/Base/PElement.xsd";
        static string xs = "http://www.w3.org/2001/XMLSchema";
        XmlSchema schema;
        private PElement pelement;

        public PElement Element
        {
            get { return pelement; }
            set { pelement = value; }
        }

        public PElementXmlSerializtion()
        {
            Assembly asm = Assembly.GetExecutingAssembly();//讀取嵌入式資源
            Stream sm = asm.GetManifestResourceStream("EFFC.Net.xsd.Parameters.PElement.xsd");
            schema = System.Xml.Schema.XmlSchema.Read(sm, null);
        }

        public static XmlQualifiedName GetSchema(XmlSchemaSet schemaSet)
        {

//            string schemaString = @"<xs:schema id='PElement'
//    targetNamespace='"+ns+@"'
//    elementFormDefault='qualified'
//    xmlns='" + ns + @"'
//    xmlns:mstns='" + ns + @"'
//    xmlns:xs='http://www.w3.org/2001/XMLSchema'
//    attributeFormDefault='unqualified'
//>
//  <!-- 简易元素的定义 -->
//  <xs:element name='Name' type='xs:string' nillable='false'></xs:element>
//  <xs:element name='PType' type='xs:string' nillable='false'></xs:element>
//  <xs:element name='Value' type='xs:base64Binary'></xs:element>
//  <!-- 属性的定义 -->
//  <!-- 复合元素的定义 -->
//  <xs:complexType name='PElement'>
//    <xs:sequence>
//      <xs:element ref='Name' ></xs:element>
//      <xs:element ref='PType'></xs:element>
//      <xs:element ref='Value'></xs:element>
//    </xs:sequence>
//  </xs:complexType>
//</xs:schema>";

            //XmlSchema schema = XmlSchema.Read(new StringReader(schemaString), null);
            //schemaSet.XmlResolver = new XmlUrlResolver();
            //schemaSet.Add(schema);

            //return new XmlQualifiedName("PElement", ns);
            throw new NotImplementedException("IXmlSerializable.GetSchema() is not implemented. Use static GetSchema() instead.");
        }

        public System.Xml.Schema.XmlSchema GetSchema()
        {
            //Assembly asm = Assembly.GetExecutingAssembly();//读取嵌入式资源
            //Stream sm = asm.GetManifestResourceStream("EFFC.Net.xsd.Parameters.PElement.xsd");
            //System.Xml.Schema.XmlSchema sc = System.Xml.Schema.XmlSchema.Read(sm, null);

            return schema;
            //return null;
            throw new NotImplementedException("IXmlSerializable.GetSchema() is not implemented. Use static GetSchema() instead.");
        }

        public void ReadXml(System.Xml.XmlReader reader)
        {
            pelement = new PElement("");

            while (reader.IsStartElement())
            {
                reader.MoveToContent();
                reader.Read();

                if (reader.IsStartElement("Name"))
                {
                    reader.MoveToContent();
                    pelement.Name = reader.ReadString();
                    reader.MoveToContent();
                    reader.ReadEndElement();
                }
                else
                    throw new BizException("ExpectedElementMissing: Name element was expected.");

                if (reader.IsStartElement("PType"))
                {
                    reader.MoveToContent();
                    pelement.PType = Type.GetType(reader.ReadString(), true, true);
                    reader.MoveToContent();
                    reader.ReadEndElement();
                }
                else
                    throw new BizException("ExpectedElementMissing: PType element was expected.");

                if (reader.IsStartElement("Value"))
                {
                    reader.MoveToContent();
                    //讀取二進制流數據
                    MemoryStream ms = new MemoryStream();
                    BinaryWriter bw = new BinaryWriter(ms);
                    byte[] buffer = new byte[1000];
                    int readBytes = 0;
                    try
                    {
                        while ((readBytes = reader.ReadElementContentAsBase64(buffer, 0, 50)) > 0)
                        {
                            bw.Write(buffer, 0, readBytes);
                        }
                    }
                    finally
                    {
                        ms.Close();
                    }

                    pelement.Value = ReadValue(pelement.PType, ms);

                    reader.MoveToContent();
                    reader.ReadEndElement();
                }
                else
                    throw new BizException("ExpectedElementMissing: Value element was expected.");

                reader.MoveToContent();
                reader.ReadEndElement();
            }
        }
        /// <summary>
        /// 从二進制流中读取数据
        /// </summary>
        /// <param name="ptype"></param>
        /// <param name="s"></param>
        /// <returns></returns>
        private object ReadValue(Type ptype, Stream s)
        {
            object rtn = null;
            //判斷是否可以序列化
            if (ptype.IsSerializable)
            {
                BinaryFormatter b = new BinaryFormatter();
                rtn = (ISerializable)b.Deserialize(s);
            }
            else if (ptype.BaseType == typeof(Stream))
            {
                rtn = s;
            }
            else
            {
                byte[] bytes = new byte[s.Length];
                s.Read(bytes, 0, bytes.Length);
                string str = Encoding.UTF8.GetString(bytes);
                rtn = Convert.ChangeType(str, ptype);
            }
            return rtn;
        }

        public void WriteXml(System.Xml.XmlWriter writer)
        {
            //Name元素
            writer.WriteStartElement("Name", ns);
            writer.WriteValue(pelement.Name);
            writer.WriteEndElement();
            //數據類型元素
            writer.WriteStartElement("PType", ns);
            writer.WriteValue(pelement.PType.FullName);
            writer.WriteEndElement();
            //Value
            writer.WriteStartElement("Value", ns);
            //判斷值是否為可序列化的數據
            if (pelement.Value is ISerializable)
            {
                //Value
                MemoryStream ms = new MemoryStream();
                BinaryFormatter b = new BinaryFormatter();
                b.Serialize(ms, pelement.Value);
                ms.Seek(0, SeekOrigin.Begin);
                BinaryReader br = new BinaryReader(ms);
                int bufferSize = 1024;
                byte[] buffer = new byte[bufferSize];
                int readBytes = 0;
                try
                {
                    do
                    {
                        readBytes = br.Read(buffer, 0, bufferSize);
                        writer.WriteBase64(buffer, 0, readBytes);
                    } while (bufferSize <= readBytes);
                }
                finally
                {
                    br.Close();
                }
            }
            else if (pelement.Value is Stream)
            {
                BinaryReader br = new BinaryReader((Stream)pelement.Value);
                int bufferSize = 1024;
                byte[] buffer = new byte[bufferSize];
                int readBytes = 0;
                try
                {
                    do
                    {
                        readBytes = br.Read(buffer, 0, bufferSize);
                        writer.WriteBase64(buffer, 0, readBytes);
                    } while (bufferSize <= readBytes);
                }
                finally
                {
                    br.Close();
                }
            }
            else
            {
                byte[] bytes = Encoding.UTF8.GetBytes(pelement.Value.ToString());
                writer.WriteBase64(bytes, 0, bytes.Length);
            }
            writer.WriteEndElement();

        }
    }

}
